package org.qs.webservice.sign;

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RSA
{
  private static String privateKeyString = "154675090652457423479960369567556491845272466849871965752808329292601765301432202972515386996683942876367051212687502203609118879973698134900143229862623253537394437541723809262856768075117211946599578322023597285130960233759234390890881187177378931490878000648469606327014113499731885663099232534214706924833";
  private static String publicKeyString = "65537";
  private static String modulusString = "164187583674928768425755794304323773988720791382249093287039188157584092850015586106409797823156390740014049810915141430481548818218922168236972576214880818766231311045415600935043457936204749451797689598294857266935350231024971989284410124472595276815118547524770945295666312296320909258402804334902622381903";

  protected byte[] encrypt(RSAPublicKey publicKey, byte[] srcBytes)
    throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
  {
    if (publicKey != null)
    {
      Cipher cipher = Cipher.getInstance("RSA");

      cipher.init(1, publicKey);

      byte[] resultBytes = cipher.doFinal(srcBytes);
      return resultBytes;
    }
    return null;
  }

  protected byte[] decrypt(RSAPrivateKey privateKey, byte[] srcBytes)
    throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
  {
    if (privateKey != null)
    {
      Cipher cipher = Cipher.getInstance("RSA");

      cipher.init(2, privateKey);

      byte[] resultBytes = cipher.doFinal(srcBytes);
      return resultBytes;
    }
    return null;
  }

  public static String sign(String msg)
  {
    RSA rsa = new RSA();

    RSAPublicKey publicKey = getPublicKey(modulusString, publicKeyString);

    byte[] srcBytes = msg.getBytes();
    try
    {
      byte[] resultBytes = rsa.encrypt(publicKey, srcBytes);
      return new String(Base64.encode(resultBytes));
    }
    catch (InvalidKeyException e)
    {
      e.printStackTrace();
    }
    catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
    catch (NoSuchPaddingException e) {
      e.printStackTrace();
    }
    catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    }
    catch (BadPaddingException e) {
      e.printStackTrace();
    }
    return "";
  }
  public static String decrypt(String msg) {
    RSA rsa = new RSA();

    RSAPrivateKey privateKey = getPrivateKey(modulusString, privateKeyString);

    byte[] srcBytes = Base64.decode(msg);
    try
    {
      byte[] resultBytes = rsa.decrypt(privateKey, srcBytes);

      return new String(resultBytes);
    }
    catch (InvalidKeyException e) {
      e.printStackTrace();
    }
    catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
    catch (NoSuchPaddingException e) {
      e.printStackTrace();
    }
    catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    }
    catch (BadPaddingException e) {
      e.printStackTrace();
    }
    return "";
  }

  public static RSAPublicKey getPublicKey(String modulus, String exponent)
  {
    try
    {
      BigInteger b1 = new BigInteger(modulus);
      BigInteger b2 = new BigInteger(exponent);
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
      return (RSAPublicKey)keyFactory.generatePublic(keySpec);
    } catch (Exception e) {
      e.printStackTrace();
    }return null;
  }

  public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
    try {
      BigInteger b1 = new BigInteger(modulus);
      BigInteger b2 = new BigInteger(exponent);
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
      return (RSAPrivateKey)keyFactory.generatePrivate(keySpec);
    } catch (Exception e) {
      e.printStackTrace();
    }return null;
  }
}